package lee.vioson.ebook.viewmodels

import androidx.lifecycle.viewModelScope
import com.laiyifen.lyftoast.ToastUtils
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import lee.vioson.composecommon.base.mvi.BaseViewModel
import lee.vioson.composecommon.base.mvi.Reducer
import lee.vioson.composecommon.base.mvi.UiEvent
import lee.vioson.composecommon.base.mvi.UiState
import lee.vioson.ebook.R
import lee.vioson.ebook.data.AppContainer
import lee.vioson.remotedata.bean.Book

/**
 *Author:viosonlee
 *Date:2023/6/15
 *DESCRIPTION:
 */
class SearchViewModel(private val appContainer: AppContainer) :
    AppViewModel<SearchViewModel.State, SearchViewModel.Event>(appContainer.appEvent) {

    private val reducer = SubReducer(State())

    override val state: StateFlow<State>
        get() = reducer.state

    override fun sendEvent(event: Event) {
        reducer.sendEvent(event)
    }

    fun doSearch(page: Int, keyword: String) {
        if (keyword.isEmpty()) {
            ToastUtils.showError(
                appContainer.context,
                appContainer.stringResource(R.string.please_input_keyword)
            )
        } else {
            doSearchRequest(page, keyword)
        }
    }

    private fun doSearchRequest(page: Int, keyword: String) =
        appContainer.bookRepository.doSearch(page, keyword)
            .catch { handleException(it) }
            .onStart {
                showLoading()
                sendEvent(Event.OnShowResultLabel(false))
            }
            .onCompletion { dismissLoading() }
            .onEach {
                sendEvent(Event.OnShowResultLabel(true))
                if (page == 1) {
                    sendEvent(Event.OnSearchResult(it))
                } else {
                    sendEvent(Event.OnSearchAddResult(it))
                }
            }
            .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)
            .launchIn(viewModelScope)

    private class SubReducer(initialState: State) :
        Reducer<State, Event>(initialState) {
        override fun reduce(oldState: State, event: Event) {
            when (event) {
                is Event.OnSearchResult -> setState(oldState.copy(results = event.list))
                is Event.OnSearchAddResult -> {
                    val list = oldState.results.toMutableList()
                    list.addAll(event.pageList)
                    setState(oldState.copy(results = list))
                }

                is Event.OnShowResultLabel -> setState(oldState.copy(showResultLabel = event.showResultLabel))
                is Event.OnPageChange -> setState(oldState.copy(page = event.page))
                is Event.OnKeywordChange -> setState(oldState.copy(keyword = event.keyword))
            }
        }
    }


    sealed class Event : UiEvent {
        data class OnSearchResult(val list: List<Book>) : Event()
        data class OnSearchAddResult(val pageList: List<Book>) : Event()
        data class OnShowResultLabel(val showResultLabel: Boolean) : Event()
        data class OnKeywordChange(val keyword: String) : Event()
        data class OnPageChange(val page: Int) : Event()
    }

    data class State(
        val keyword: String = "",
        val results: List<Book> = emptyList(),
        val page: Int = 1,
        val showResultLabel: Boolean = false
    ) : UiState
}

